home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / graph3d.c < prev    next >
C/C++ Source or Header  |  1998-12-04  |  58KB  |  1,967 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graph3d.c,v 1.106 1998/06/18 14:55:07 ddenholm Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - graph3d.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37.  
  38. /*
  39.  * AUTHORS
  40.  *
  41.  *   Original Software:
  42.  *       Gershon Elber and many others.
  43.  *
  44.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  45.  * Added user-specified bases for log scaling.
  46.  *
  47.  * 3.6 - split graph3d.c into graph3d.c (graph),
  48.  *                            util3d.c (intersections, etc)
  49.  *                            hidden3d.c (hidden-line removal code)
  50.  *
  51.  */
  52.  
  53. #include "plot.h"
  54. #include "setshow.h"
  55.  
  56. static int p_height;
  57. static int p_width;        /* pointsize * t->h_tic */
  58. static int key_entry_height;    /* bigger of t->v_size, pointsize*t->v_tick */
  59.  
  60. int suppressMove = 0;        /* to prevent moveto while drawing contours */
  61.  
  62. /*
  63.  * hidden_line_type_above, hidden_line_type_below - controls type of lines
  64.  *   for above and below parts of the surface.
  65.  * hidden_no_update - if TRUE lines will be hidden line removed but they
  66.  *   are not assumed to be part of the surface (i.e. grid) and therefore
  67.  *   do not influence the hidings.
  68.  * hidden_active - TRUE if hidden lines are to be removed.
  69.  */
  70. int hidden_active = FALSE;
  71. int hidden_no_update;        /* HBB 980324: made this visible despite LITE */
  72.  
  73. /* LITE defines a restricted memory version for MS-DOS, which doesn't
  74.  * use the routines in hidden3d.c
  75.  */
  76.  
  77. #ifndef LITE
  78. int hidden_line_type_above, hidden_line_type_below;
  79. #endif /* LITE */
  80.  
  81.  
  82. static double LogScale __PROTO((double coord, TBOOLEAN is_log,
  83.                 double log_base_log, char *what, char *axis));
  84. static void plot3d_impulses __PROTO((struct surface_points * plot));
  85. static void plot3d_lines __PROTO((struct surface_points * plot));
  86. static void plot3d_points __PROTO((struct surface_points * plot));
  87. static void plot3d_dots __PROTO((struct surface_points * plot));
  88. static void cntr3d_impulses __PROTO((struct gnuplot_contours * cntr,
  89.                      struct surface_points * plot));
  90. static void cntr3d_lines __PROTO((struct gnuplot_contours * cntr));
  91. static void cntr3d_points __PROTO((struct gnuplot_contours * cntr,
  92.                    struct surface_points * plot));
  93. static void cntr3d_dots __PROTO((struct gnuplot_contours * cntr));
  94. static void check_corner_height __PROTO((struct coordinate GPHUGE * point,
  95.                      double height[2][2], double depth[2][2]));
  96. static void draw_bottom_grid __PROTO((struct surface_points * plot,
  97.                       int plot_count));
  98. static void xtick_callback __PROTO((int axis, double place, char *text,
  99.                     struct lp_style_type grid));
  100. static void ytick_callback __PROTO((int axis, double place, char *text,
  101.                     struct lp_style_type grid));
  102. static void ztick_callback __PROTO((int axis, double place, char *text,
  103.                     struct lp_style_type grid));
  104. static void setlinestyle __PROTO((struct lp_style_type style));
  105.  
  106. static void boundary3d __PROTO((int scaling, struct surface_points * plots,
  107.                 int count));
  108. #if 0                /* not used */
  109. static double dbl_raise __PROTO((double x, int y));
  110. #endif
  111. static void map_position __PROTO((struct position * pos, unsigned int *x,
  112.                   unsigned int *y, char *what));
  113.  
  114. /* put entries in the key */
  115. static void key_sample_line __PROTO((int xl, int yl));
  116. static void key_sample_point __PROTO((int xl, int yl, int pointtype));
  117. static void key_text __PROTO((int xl, int yl, char *text));
  118.  
  119.  
  120. #if defined(sun386) || defined(AMIGA_SC_6_1)
  121. static double CheckLog __PROTO((TBOOLEAN is_log, double base_log, double x));
  122. #endif
  123.  
  124. /*
  125.  * The Amiga SAS/C 6.2 compiler moans about macro envocations causing
  126.  * multiple calls to functions. I converted these macros to inline
  127.  * functions coping with the problem without loosing speed.
  128.  * (MGR, 1993)
  129.  */
  130. #ifdef AMIGA_SC_6_1
  131. GP_INLINE static TBOOLEAN i_inrange(int z, int min, int max)
  132. {
  133.     return ((min < max) ? ((z >= min) && (z <= max)) : ((z >= max) && (z <= min)));
  134. }
  135.  
  136. GP_INLINE static double f_max(double a, double b)
  137. {
  138.     return (max(a, b));
  139. }
  140.  
  141. GP_INLINE static double f_min(double a, double b)
  142. {
  143.     return (min(a, b));
  144. }
  145.  
  146. #else
  147. # define f_max(a,b) GPMAX((a),(b))
  148. # define f_min(a,b) GPMIN((a),(b))
  149. # define i_inrange(z,a,b) inrange((z),(a),(b))
  150. #endif
  151.  
  152. #define apx_eq(x,y) (fabs(x-y) < 0.001)
  153. #define ABS(x) ((x) >= 0 ? (x) : -(x))
  154. #define SQR(x) ((x) * (x))
  155.  
  156. /* Define the boundary of the plot
  157.  * These are computed at each call to do_plot, and are constant over
  158.  * the period of one do_plot. They actually only change when the term
  159.  * type changes and when the 'set size' factors change. 
  160.  */
  161.  
  162. /* in order to allow graphic.c to use clip_draw_line, we must
  163.  * share xleft, xright, ybot, ytop with graphics.c
  164.  */
  165. extern int xleft, xright, ybot, ytop;
  166.  
  167. int xmiddle, ymiddle, xscaler, yscaler;
  168. static int ptitl_cnt;
  169. static int max_ptitl_len;
  170. static int titlelin;
  171. static int key_sample_width, key_rows, key_cols, key_col_wth, yl_ref;
  172. static int ktitle_lines = 0;
  173.  
  174.  
  175. /* Boundary and scale factors, in user coordinates */
  176. /* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
  177.  * file and are not the same as variables of the same names in other files
  178.  */
  179. /*static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d; */
  180. /* sizes are now set in min_array[], max_array[] from plot.c */
  181. extern double min_array[], max_array[];
  182. extern int auto_array[], log_array[];
  183. extern double base_array[], log_base_array[];
  184.  
  185. /* for convenience while converting to use these arrays */
  186. #define x_min3d min_array[FIRST_X_AXIS]
  187. #define x_max3d max_array[FIRST_X_AXIS]
  188. #define y_min3d min_array[FIRST_Y_AXIS]
  189. #define y_max3d max_array[FIRST_Y_AXIS]
  190. #define z_min3d min_array[FIRST_Z_AXIS]
  191. #define z_max3d max_array[FIRST_Z_AXIS]
  192.  
  193. /* There are several z's to take into account - I hope I get these
  194.  * right !
  195.  *
  196.  * ceiling_z is the highest z in use
  197.  * floor_z   is the lowest z in use
  198.  * base_z is the z of the base
  199.  * min3d_z is the lowest z of the graph area
  200.  * max3d_z is the highest z of the graph area
  201.  *
  202.  * ceiling_z is either max3d_z or base_z, and similarly for floor_z
  203.  * There should be no part of graph drawn outside
  204.  * min3d_z:max3d_z  - apart from arrows, perhaps
  205.  */
  206.  
  207. double ceiling_z, floor_z, base_z;
  208.  
  209. /* and some bodges while making the change */
  210. #define min3d_z min_array[FIRST_Z_AXIS]
  211. #define max3d_z max_array[FIRST_Z_AXIS]
  212.  
  213.  
  214. double xscale3d, yscale3d, zscale3d;
  215.  
  216.  
  217. typedef double transform_matrix[4][4];
  218. transform_matrix trans_mat;
  219.  
  220. static double xaxis_y, yaxis_x, zaxis_x, zaxis_y;
  221.  
  222. /* the co-ordinates of the back corner */
  223. static double back_x, back_y;
  224.  
  225. /* the penalty for convenience of using tic_gen to make callbacks
  226.  * to tick routines is that we cant pass parameters very easily.
  227.  * We communicate with the tick_callbacks using static variables
  228.  */
  229.  
  230. /* unit vector (terminal coords) */
  231. static double tic_unitx, tic_unity;
  232.  
  233. /* (DFK) Watch for cancellation error near zero on axes labels */
  234. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  235. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  236. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  237.  
  238. /* And the functions to map from user to terminal coordinates */
  239. #define map_x(x) (int)(x+0.5)    /* maps floating point x to screen */
  240. #define map_y(y) (int)(y+0.5)    /* same for y */
  241.  
  242. /* And the functions to map from user 3D space into normalized -1..1 */
  243. #define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
  244. #define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
  245. #define map_z3d(z) ((z-floor_z)*zscale3d-1.0)
  246.  
  247.  
  248.  
  249. /* Initialize the line style using the current device and set hidden styles
  250.  * to it as well if hidden line removal is enabled */
  251. static void setlinestyle(style)
  252. struct lp_style_type style;
  253. {
  254.     term_apply_lp_properties(&style);
  255.  
  256. #ifndef LITE
  257.     if (hidden3d) {
  258.     hidden_line_type_above = style.l_type;
  259.     hidden_line_type_below = style.l_type;
  260.     }
  261. #endif /* LITE */
  262. }
  263.  
  264. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  265.  * macro, so I write it as a function on that machine.
  266.  *
  267.  * Amiga SAS/C 6.2 thinks it will do too much work calling functions in
  268.  * macro arguments twice, thus I inline theese functions. (MGR, 1993)
  269.  */
  270. #if defined(sun386) || defined(AMIGA_SC_6_1)
  271. GP_INLINE static double CheckLog(is_log, base_log, x)
  272. TBOOLEAN is_log;
  273. double base_log;
  274. double x;
  275. {
  276.     if (is_log)
  277.     return (pow(base_log, x));
  278.     else
  279.     return (x);
  280. }
  281. #else
  282. /* (DFK) Use 10^x if logscale is in effect, else x */
  283. # define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  284. #endif /* sun386 || SAS/C */
  285.  
  286. static double LogScale(coord, is_log, log_base_log, what, axis)
  287. double coord;            /* the value */
  288. TBOOLEAN is_log;        /* is this axis in logscale? */
  289. double log_base_log;        /* if so, the log of its base */
  290. char *what;            /* what is the coord for? */
  291. char *axis;            /* which axis is this for ("x" or "y")? */
  292. {
  293.     if (is_log) {
  294.     if (coord <= 0.0) {
  295.         char errbuf[100];    /* place to write error message */
  296.         (void) sprintf(errbuf, "%s has %s coord of %g; must be above 0 for log scale!",
  297.                what, axis, coord);
  298.         graph_error(errbuf);
  299.     } else
  300.         return (log(coord) / log_base_log);
  301.     }
  302.     return (coord);
  303. }
  304.  
  305. /* And the functions to map from user 3D space to terminal coordinates */
  306. void map3d_xy(x, y, z, xt, yt)
  307. double x, y, z;
  308. unsigned int *xt, *yt;
  309. {
  310.     int i, j;
  311.     double v[4], res[4], /* Homogeneous coords. vectors. */
  312.     w = trans_mat[3][3];
  313.  
  314.     v[0] = map_x3d(x);        /* Normalize object space to -1..1 */
  315.     v[1] = map_y3d(y);
  316.     v[2] = map_z3d(z);
  317.     v[3] = 1.0;
  318.  
  319.     for (i = 0; i < 2; i++) {    /* Dont use the third axes (z). */
  320.     res[i] = trans_mat[3][i];    /* Initiate it with the weight factor */
  321.     for (j = 0; j < 3; j++)
  322.         res[i] += v[j] * trans_mat[j][i];
  323.     }
  324.  
  325.     for (i = 0; i < 3; i++)
  326.     w += v[i] * trans_mat[i][3];
  327.     if (w == 0)
  328.     w = 1e-5;
  329.  
  330.     *xt = (unsigned int) ((res[0] * xscaler / w) + xmiddle);
  331.     *yt = (unsigned int) ((res[1] * yscaler / w) + ymiddle);
  332. }
  333.  
  334.  
  335.  
  336. /* And the functions to map from user 3D space to terminal z coordinate */
  337. int map3d_z(x, y, z)
  338. double x, y, z;
  339. {
  340.     int i, zt;
  341.     double v[4], res, /* Homogeneous coords. vectors. */
  342.     w = trans_mat[3][3];
  343.  
  344.     v[0] = map_x3d(x);        /* Normalize object space to -1..1 */
  345.     v[1] = map_y3d(y);
  346.     v[2] = map_z3d(z);
  347.     v[3] = 1.0;
  348.  
  349.     res = trans_mat[3][2];    /* Initiate it with the weight factor. */
  350.     for (i = 0; i < 3; i++)
  351.     res += v[i] * trans_mat[i][2];
  352.     if (w == 0)
  353.     w = 1e-5;
  354.     for (i = 0; i < 3; i++)
  355.     w += v[i] * trans_mat[i][3];
  356.     zt = ((int) (res * 16384 / w));
  357.     return zt;
  358. }
  359.  
  360. /* borders of plotting area */
  361. /* computed once on every call to do_plot */
  362. static void boundary3d(scaling, plots, count)
  363. TBOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  364. struct surface_points *plots;
  365. int count;
  366. {
  367.     register struct termentry *t = term;
  368.     int ytlen, i;
  369.  
  370.     titlelin = 0;
  371.  
  372.     p_height = pointsize * t->v_tic;
  373.     p_width = pointsize * t->h_tic;
  374.     if (key_swidth >= 0)
  375.     key_sample_width = key_swidth * (t->h_char) + pointsize * (t->h_tic);
  376.     else
  377.     key_sample_width = 0;
  378.     key_entry_height = pointsize * (t->v_tic) * 1.25 * key_vert_factor;
  379.     if (key_entry_height < (t->v_char)) {
  380.     /* is this reasonable ? */
  381.     key_entry_height = (t->v_char) * key_vert_factor;
  382.     }
  383.  
  384.     /* count max_len key and number keys (plot-titles and contour labels) with len > 0 */
  385.     max_ptitl_len = find_maxl_keys3d(plots, count, &ptitl_cnt);
  386.     if ((ytlen = label_width(key_title, &ktitle_lines)) > max_ptitl_len)
  387.     max_ptitl_len = ytlen;
  388.     key_col_wth = (max_ptitl_len + 4) * (t->h_char) + key_sample_width;
  389.  
  390.     /* luecken@udel.edu modifications
  391.        sizes the plot to take up more of available resolution */
  392.     if (lmargin >= 0)
  393.     xleft = (t->h_char) * lmargin;
  394.     else
  395.     xleft = (t->h_char) * 2 + (t->h_tic);
  396.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char) * 2 - (t->h_tic);
  397.     key_rows = ptitl_cnt;
  398.     key_cols = 1;
  399.     if (key == -1 && key_vpos == TUNDER) {
  400.     /* calculate max no cols, limited by label-length */
  401.     key_cols = (int) (xright - xleft) / ((max_ptitl_len + 4) * (t->h_char) + key_sample_width);
  402.     key_rows = (int) (ptitl_cnt / key_cols) + ((ptitl_cnt % key_cols) > 0);
  403.     /* now calculate actual no cols depending on no rows */
  404.     key_cols = (int) (ptitl_cnt / key_rows) + ((ptitl_cnt % key_rows) > 0);
  405.     key_col_wth = (int) (xright - xleft) / key_cols;
  406.     /* key_rows += ktitle_lines; - messes up key - div */
  407.     }
  408.     /* this should also consider the view and number of lines in
  409.      * xformat || yformat || xlabel || ylabel */
  410.  
  411.     /* an absolute 1, with no terminal-dependent scaling ? */
  412.     ybot = (t->v_char) * 2.5 + 1;
  413.     if (key_rows && key_vpos == TUNDER)
  414.     ybot += key_rows * key_entry_height + ktitle_lines * t->v_char;
  415.  
  416.     if (strlen(title.text)) {
  417.     titlelin++;
  418.     for (i = 0; i < strlen(title.text); i++) {
  419.         if (title.text[i] == '\\')
  420.         titlelin++;
  421.     }
  422.     }
  423.     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char) * (titlelin + 1.5) - 1;
  424.     if (key == -1 && key_vpos != TUNDER) {
  425.     /* calculate max no rows, limited be ytop-ybot */
  426.     i = (int) (ytop - ybot) / (t->v_char) - 1 - ktitle_lines;
  427.     if (ptitl_cnt > i) {
  428.         key_cols = (int) (ptitl_cnt / i) + ((ptitl_cnt % i) > 0);
  429.         /* now calculate actual no rows depending on no cols */
  430.         key_rows = (int) (ptitl_cnt / key_cols) + ((ptitl_cnt % key_cols) > 0);
  431.     }
  432.     key_rows += ktitle_lines;
  433.     }
  434.     if (key_hpos == TOUT) {
  435.     xright -= key_col_wth * (key_cols - 1) + key_col_wth - 2 * (t->h_char);
  436.     }
  437.     xleft += t->xmax * xoffset;
  438.     xright += t->xmax * xoffset;
  439.     ytop += t->ymax * yoffset;
  440.     ybot += t->ymax * yoffset;
  441.     xmiddle = (xright + xleft) / 2;
  442.     ymiddle = (ytop + ybot) / 2;
  443.     /* HBB 980308: sigh... another 16bit glitch: on term's with more than
  444.      * 8000 pixels in either direction, these calculations produce garbage
  445.      * results if done in (16bit) ints */
  446.     xscaler = (xright - xleft) * 4 / 7;        /* HBB: Magic number alert! */
  447.     yscaler = ((ytop - ybot) * 4L) / 7L;
  448.  
  449. }
  450.  
  451. #if 0
  452. /* not used ; anyway, should be done using bitshifts and squares,
  453.  * rather than iteratively
  454.  */
  455. static double dbl_raise(x, y)
  456. double x;
  457. int y;
  458. {
  459.     register int i = ABS(y);
  460.     double val = 1.0;
  461.     while (--i >= 0)
  462.     val *= x;
  463.     if (y < 0)
  464.     return (1.0 / val);
  465.     return (val);
  466. }
  467. #endif
  468.  
  469. /* we precalculate features of the key, to save lots of nested
  470.  * ifs in code - x,y = user supplied or computed position of key
  471.  * taken to be inner edge of a line sample
  472.  */
  473. static int key_sample_left;    /* offset from x for left of line sample */
  474. static int key_sample_right;    /* offset from x for right of line sample */
  475. static int key_point_offset;    /* offset from x for point sample */
  476. static int key_text_left;    /* offset from x for left-justified text */
  477. static int key_text_right;    /* offset from x for right-justified text */
  478. static int key_size_left;    /* distance from x to left edge of box */
  479. static int key_size_right;    /* distance from x to right edge of box */
  480.  
  481. void do_3dplot(plots, pcount)
  482. struct surface_points *plots;
  483. int pcount;            /* count of plots in linked list */
  484. {
  485.     struct termentry *t = term;
  486.     int surface;
  487.     struct surface_points *this_plot = NULL;
  488.     unsigned int xl, yl;
  489.     int linetypeOffset = 0;
  490.     double ztemp, temp;
  491.     struct text_label *this_label;
  492.     struct arrow_def *this_arrow;
  493.     TBOOLEAN scaling;
  494.     transform_matrix mat;
  495.     int key_count;
  496.     char ss[MAX_LINE_LEN+1], *s, *e;
  497.  
  498.     /* Initiate transformation matrix using the global view variables. */
  499.     mat_rot_z(surface_rot_z, trans_mat);
  500.     mat_rot_x(surface_rot_x, mat);
  501.     mat_mult(trans_mat, trans_mat, mat);
  502.     mat_scale(surface_scale / 2.0, surface_scale / 2.0, surface_scale / 2.0, mat);
  503.     mat_mult(trans_mat, trans_mat, mat);
  504.  
  505.     /* modify min_z/max_z so it will zscale properly. */
  506.     ztemp = (z_max3d - z_min3d) / (2.0 * surface_zscale);
  507.     temp = (z_max3d + z_min3d) / 2.0;
  508.     z_min3d = temp - ztemp;
  509.     z_max3d = temp + ztemp;
  510.  
  511.  
  512.     /* The extrema need to be set even when a surface is not being
  513.      * drawn.   Without this, gnuplot used to assume that the X and
  514.      * Y axis started at zero.   -RKC
  515.      */
  516.  
  517.     if (polar)
  518.     graph_error("Cannot splot in polar coordinate system.");
  519.  
  520.     /* done in plot3d.c
  521.      *    if (z_min3d == VERYLARGE || z_max3d == -VERYLARGE ||
  522.      *      x_min3d == VERYLARGE || x_max3d == -VERYLARGE ||
  523.      *      y_min3d == VERYLARGE || y_max3d == -VERYLARGE)
  524.      *      graph_error("all points undefined!");
  525.      */
  526.  
  527.     /* If we are to draw the bottom grid make sure zmin is updated properly. */
  528.     if (xtics || ytics || work_grid.l_type) {
  529.     base_z = z_min3d - (z_max3d - z_min3d) * ticslevel;
  530.     if (ticslevel >= 0)
  531.         floor_z = base_z;
  532.     else
  533.         floor_z = z_min3d;
  534.  
  535.     if (ticslevel < -1)
  536.         ceiling_z = base_z;
  537.     else
  538.         ceiling_z = z_max3d;
  539.     } else {
  540.     floor_z = base_z = z_min3d;
  541.     ceiling_z = z_max3d;
  542.     }
  543.  
  544.     /*  see comment accompanying similar tests of x_min/x_max and y_min/y_max
  545.      *  in graphics.c:do_plot(), for history/rationale of these tests */
  546.     if (x_min3d == x_max3d)
  547.     graph_error("x_min3d should not equal x_max3d!");
  548.     if (y_min3d == y_max3d)
  549.     graph_error("y_min3d should not equal y_max3d!");
  550.     if (z_min3d == z_max3d)
  551.     graph_error("z_min3d should not equal z_max3d!");
  552.  
  553. #ifndef LITE
  554.     if (hidden3d) {
  555.     struct surface_points *plot;
  556.     int p = 0;
  557.     /* Verify data is hidden line removable - grid based. */
  558.     for (plot = plots; ++p <= pcount; plot = plot->next_sp) {
  559.         if (plot->plot_type == DATA3D && !plot->has_grid_topology) {
  560.         fprintf(stderr, "Notice: Cannot remove hidden lines from non grid data\n");
  561.         return;
  562.         }
  563.     }
  564.     }
  565. #endif /* not LITE */
  566.  
  567.     term_start_plot();
  568.  
  569.     screen_ok = FALSE;
  570.     scaling = (*t->scale) (xsize, ysize);
  571.  
  572.     /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  573.     boundary3d(scaling, plots, pcount);
  574.  
  575.     /* SCALE FACTORS */
  576.     zscale3d = 2.0 / (ceiling_z - floor_z);
  577.     yscale3d = 2.0 / (y_max3d - y_min3d);
  578.     xscale3d = 2.0 / (x_max3d - x_min3d);
  579.  
  580.     term_apply_lp_properties(&border_lp);    /* border linetype */
  581.  
  582.     /* PLACE TITLE */
  583.     if (*title.text != 0) {
  584.     safe_strncpy(ss, title.text, sizeof(ss));
  585.     write_multiline((unsigned int) ((xleft + xright) / 2 + title.xoffset * t->h_char),
  586.             (unsigned int) (ytop + (titlelin + title.yoffset) * (t->h_char)),
  587.             ss, CENTRE, JUST_TOP, 0, title.font);
  588.     }
  589.     /* PLACE TIMEDATE */
  590.     if (*timelabel.text) {
  591.     char str[MAX_LINE_LEN+1];
  592.     time_t now;
  593.     unsigned int x = t->v_char + timelabel.xoffset * t->h_char;
  594.     unsigned int y = timelabel_bottom ?
  595.     yoffset * ymax + (timelabel.yoffset + 1) * t->v_char :
  596.     ytop + (timelabel.yoffset - 1) * t->v_char;
  597.  
  598.     time(&now);
  599.     strftime(str, MAX_LINE_LEN, timelabel.text, localtime(&now));
  600.  
  601.     if (timelabel_rotate && (*t->text_angle) (1)) {
  602.         if (timelabel_bottom)
  603.         write_multiline(x, y, str, LEFT, JUST_TOP, 1, timelabel.font);
  604.         else
  605.         write_multiline(x, y, str, RIGHT, JUST_TOP, 1, timelabel.font);
  606.  
  607.         (*t->text_angle) (0);
  608.     } else {
  609.         if (timelabel_bottom)
  610.         write_multiline(x, y, str, LEFT, JUST_BOT, 0, timelabel.font);
  611.         else
  612.         write_multiline(x, y, str, LEFT, JUST_TOP, 0, timelabel.font);
  613.     }
  614.     }
  615.     /* PLACE LABELS */
  616.     for (this_label = first_label; this_label != NULL;
  617.      this_label = this_label->next) {
  618.     unsigned int x, y;
  619.  
  620.  
  621.     map_position(&this_label->place, &x, &y, "label");
  622.     safe_strncpy(ss, this_label->text, sizeof(ss));
  623.     if (this_label->rotate && (*t->text_angle) (1)) {
  624.         write_multiline(x, y, this_label->text, this_label->pos, CENTRE, 1, this_label->font);
  625.         (*t->text_angle) (0);
  626.     } else {
  627.         write_multiline(x, y, this_label->text, this_label->pos, CENTRE, 0, this_label->font);
  628.     }
  629.     }
  630.  
  631.     /* PLACE ARROWS */
  632.     for (this_arrow = first_arrow; this_arrow != NULL;
  633.      this_arrow = this_arrow->next) {
  634.     unsigned int sx, sy, ex, ey;
  635.  
  636.     map_position(&this_arrow->start, &sx, &sy, "arrow");
  637.     map_position(&this_arrow->end, &ex, &ey, "arrow");
  638.     term_apply_lp_properties(&(this_arrow->lp_properties));
  639.     (*t->arrow) (sx, sy, ex, ey, this_arrow->head);
  640.     }
  641.  
  642. #ifndef LITE
  643.     if (hidden3d && draw_surface) {
  644.     init_hidden_line_removal();
  645.     reset_hidden_line_removal();
  646.     hidden_active = TRUE;
  647.     }
  648. #endif /* not LITE */
  649.  
  650.     /* WORK OUT KEY SETTINGS AND DO KEY TITLE / BOX */
  651.  
  652.     if (key_reverse) {
  653.     key_sample_left = -key_sample_width;
  654.     key_sample_right = 0;
  655.     key_text_left = t->h_char;
  656.     key_text_right = (t->h_char) * (max_ptitl_len + 1);
  657.     key_size_right = (t->h_char) * (max_ptitl_len + 2 + key_width_fix);
  658.     key_size_left = (t->h_char) + key_sample_width;
  659.     } else {
  660.     key_sample_left = 0;
  661.     key_sample_right = key_sample_width;
  662.     key_text_left = -(int) ((t->h_char) * (max_ptitl_len + 1));
  663.     key_text_right = -(int) (t->h_char);
  664.     key_size_left = (t->h_char) * (max_ptitl_len + 2 + key_width_fix);
  665.     key_size_right = (t->h_char) + key_sample_width;
  666.     }
  667.     key_point_offset = (key_sample_left + key_sample_right) / 2;
  668.  
  669.     if (key == -1) {
  670.     if (key_vpos == TUNDER) {
  671. #if 0
  672.         yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines + 2) * t->v_char;
  673.         xl = max_ptitl_len * 1000 / (key_sample_width / (t->h_char) + max_ptitl_len + 2);
  674.         xl *= (xright - xleft) / key_cols;
  675.         xl /= 1000;
  676.         xl += xleft;
  677. #else
  678.         /* maximise no cols, limited by label-length */
  679.         key_cols = (int) (xright - xleft) / key_col_wth;
  680.         key_rows = (int) (ptitl_cnt + key_cols - 1) / key_cols;
  681.         /* now calculate actual no cols depending on no rows */
  682.         key_cols = (int) (ptitl_cnt + key_rows - 1) / key_rows;
  683.         key_col_wth = (int) (xright - xleft) / key_cols;
  684.         /* we divide into columns, then centre in column by considering
  685.          * ratio of key_left_size to key_right_size
  686.          * key_size_left/(key_size_left+key_size_right) * (xright-xleft)/key_cols
  687.          * do one integer division to maximise accuracy (hope we dont
  688.          * overflow !)
  689.          */
  690.         xl = xleft + ((xright - xleft) * key_size_left) / (key_cols * (key_size_left + key_size_right));
  691.         yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines + 2) * t->v_char;
  692. #endif
  693.     } else {
  694.         if (key_vpos == TTOP) {
  695.         yl = ytop - (t->v_tic) - t->v_char;
  696.         } else {
  697.         yl = ybot + (t->v_tic) + key_entry_height * key_rows + ktitle_lines * t->v_char;
  698.         }
  699.         if (key_hpos == TOUT) {
  700.         /* keys outside plot border (right) */
  701.         xl = xright + (t->h_tic) + key_size_left;
  702.         } else if (key_hpos == TLEFT) {
  703.         xl = xleft + (t->h_tic) + key_size_left;
  704.         } else {
  705.         xl = xright - key_size_right - key_col_wth * (key_cols - 1);
  706.         }
  707.     }
  708.     yl_ref = yl - ktitle_lines * (t->v_char);
  709.     }
  710.     if (key == 1) {
  711.     map_position(&key_user_pos, &xl, &yl, "key");
  712.     }
  713.     if (key && key_box.l_type > -3) {
  714.     int yt = yl;
  715.     int yb = yl - key_entry_height * (key_rows - ktitle_lines) - ktitle_lines * t->v_char;
  716.     int key_xr = xl + key_col_wth * (key_cols - 1) + key_size_right;
  717.     /* key_rows seems to contain title at this point ??? */
  718.     term_apply_lp_properties(&key_box);
  719.     (*t->move) (xl - key_size_left, yb);
  720.     (*t->vector) (xl - key_size_left, yt);
  721.     (*t->vector) (key_xr, yt);
  722.     (*t->vector) (key_xr, yb);
  723.     (*t->vector) (xl - key_size_left, yb);
  724.  
  725.     /* draw a horizontal line between key title and first entry  JFi */
  726.     (*t->move) (xl - key_size_left, yt - (ktitle_lines) * t->v_char);
  727.     (*t->vector) (xl + key_size_right, yt - (ktitle_lines) * t->v_char);
  728.     }
  729.     /* DRAW SURFACES AND CONTOURS */
  730.  
  731. #ifndef LITE
  732.     if (hidden3d && draw_surface)
  733.     plot3d_hidden(plots, pcount);
  734. #endif /* not LITE */
  735.  
  736.     /* KEY TITLE */
  737.     if (key != 0 && strlen(key_title)) {
  738.     sprintf(ss, "%s\n", key_title);
  739.     s = ss;
  740.     yl -= t->v_char / 2;
  741.     while ((e = (char *) strchr(s, '\n')) != NULL) {
  742.         *e = '\0';
  743.         if (key_just == JLEFT) {
  744.         (*t->justify_text) (LEFT);
  745.         (*t->put_text) (xl + key_text_left, yl, s);
  746.         } else {
  747.         if ((*t->justify_text) (RIGHT)) {
  748.             (*t->put_text) (xl + key_text_right,
  749.                     yl, s);
  750.         } else {
  751.             int x = xl + key_text_right - (t->h_char) * strlen(s);
  752.             if (inrange(x, xleft, xright))
  753.             (*t->put_text) (x, yl, s);
  754.         }
  755.         }
  756.         s = ++e;
  757.         yl -= t->v_char;
  758.     }
  759.     yl += t->v_char / 2;
  760.     }
  761.     key_count = 0;
  762.     yl_ref = yl -= key_entry_height / 2;    /* centralise the keys */
  763.  
  764. #define NEXT_KEY_LINE() \
  765.  if ( ++key_count >= key_rows ) { \
  766.    yl = yl_ref; xl += key_col_wth; key_count = 0; \
  767.  } else \
  768.    yl -= key_entry_height
  769.  
  770.     this_plot = plots;
  771.     for (surface = 0;
  772.      surface < pcount;
  773.      this_plot = this_plot->next_sp, surface++) {
  774.  
  775. #ifndef LITE
  776.     if (hidden3d)
  777.         hidden_no_update = FALSE;
  778. #endif /* not LITE */
  779.  
  780.     if (draw_surface) {
  781.         int lkey = (key != 0 && this_plot->title && this_plot->title[0]);
  782.         term_apply_lp_properties(&(this_plot->lp_properties));
  783.  
  784. #ifndef LITE
  785.         if (hidden3d) {
  786.         hidden_line_type_above = this_plot->lp_properties.l_type;
  787.         hidden_line_type_below = this_plot->lp_properties.l_type + 1;
  788.         }
  789. #endif /* not LITE */
  790.  
  791.         if (lkey) {
  792.         key_text(xl, yl, this_plot->title);
  793.         }
  794.         switch (this_plot->plot_style) {
  795.         case BOXES:    /* can't do boxes in 3d yet so use impulses */
  796.         case IMPULSES:{
  797.             if (lkey) {
  798.             key_sample_line(xl, yl);
  799.             }
  800.             if (!(hidden3d && draw_surface))
  801.             plot3d_impulses(this_plot);
  802.             break;
  803.         }
  804.         case STEPS:    /* HBB: I think these should be here */
  805.         case FSTEPS:
  806.         case HISTEPS:
  807.         case LINES:{
  808.             if (lkey) {
  809.             key_sample_line(xl, yl);
  810.             }
  811.             if (!(hidden3d && draw_surface))
  812.             plot3d_lines(this_plot);
  813.             break;
  814.         }
  815.         case YERRORBARS:    /* ignored; treat like points */
  816.         case XERRORBARS:    /* ignored; treat like points */
  817.         case XYERRORBARS:    /* ignored; treat like points */
  818.         case BOXXYERROR:    /* HBB: ignore these as well */
  819.         case BOXERROR:
  820.         case CANDLESTICKS:    /* HBB: dito */
  821.         case FINANCEBARS:
  822.         case VECTOR:
  823.         case POINTSTYLE:
  824.         if (lkey && !clip_point(xl + key_point_offset, yl)) {
  825.             key_sample_point(xl, yl, this_plot->lp_properties.p_type);
  826.         }
  827.         if (!(hidden3d && draw_surface))
  828.             plot3d_points(this_plot);
  829.         break;
  830.  
  831.         case LINESPOINTS:
  832.         /* put lines */
  833.         if (lkey)
  834.             key_sample_line(xl, yl);
  835.  
  836.         if (!(hidden3d && draw_surface))
  837.             plot3d_lines(this_plot);
  838.  
  839.         /* put points */
  840.         if (lkey && !clip_point(xl + key_point_offset, yl))
  841.             key_sample_point(xl, yl, this_plot->lp_properties.p_type);
  842.  
  843.         if (!(hidden3d && draw_surface))
  844.             plot3d_points(this_plot);
  845.  
  846.         break;
  847.  
  848.         case DOTS:
  849.         if (lkey) {
  850.             if (key == 1) {
  851.             if (!clip_point(xl + key_point_offset, yl))
  852.                 (*t->point) (xl + key_point_offset, yl, -1);
  853.             } else {
  854.             (*t->point) (xl + key_point_offset, yl, -1);
  855.             /* (*t->point)(xl+2*(t->h_char),yl, -1); */
  856.             }
  857.         }
  858.         if (!(hidden3d && draw_surface))
  859.             plot3d_dots(this_plot);
  860.  
  861.         break;
  862.  
  863.  
  864.         }            /* switch(plot-style) */
  865.  
  866.         /* move key on a line */
  867.         if (lkey) {
  868.         NEXT_KEY_LINE();
  869.         }
  870.     }            /* draw_surface */
  871.  
  872. #ifndef LITE 
  873.     if (hidden3d) {
  874.         hidden_no_update = TRUE;
  875.         hidden_line_type_above = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
  876.         hidden_line_type_below = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
  877.     }
  878. #endif /* not LITE */
  879.  
  880.     if (draw_contour && this_plot->contours != NULL) {
  881.         struct gnuplot_contours *cntrs = this_plot->contours;
  882.  
  883.         term_apply_lp_properties(&(this_plot->lp_properties));
  884.         (*t->linetype) (this_plot->lp_properties.l_type + (hidden3d ? 2 : 1));
  885.  
  886.         if (key != 0 && this_plot->title && this_plot->title[0]
  887.         && !draw_surface && !label_contours) {
  888.         /* unlabelled contours but no surface : put key entry in now */
  889.         key_text(xl, yl, this_plot->title);
  890.  
  891.         switch (this_plot->plot_style) {
  892.         case IMPULSES:
  893.         case LINES:
  894.         case BOXES:    /* HBB: I think these should be here... */
  895.         case STEPS:
  896.         case FSTEPS:
  897.         case HISTEPS:
  898.             key_sample_line(xl, yl);
  899.             break;
  900.         case YERRORBARS:    /* ignored; treat like points */
  901.         case XERRORBARS:    /* ignored; treat like points */
  902.         case XYERRORBARS:    /* ignored; treat like points */
  903.         case BOXERROR:    /* HBB: ignore these as well */
  904.         case BOXXYERROR:
  905.         case CANDLESTICKS:    /* HBB: dito */
  906.         case FINANCEBARS:
  907.         case VECTOR:
  908.         case POINTSTYLE:
  909.             key_sample_point(xl, yl, this_plot->lp_properties.p_type);
  910.             break;
  911.         case LINESPOINTS:
  912.             key_sample_line(xl, yl);
  913.             break;
  914.         case DOTS:
  915.             key_sample_point(xl, yl, -1);
  916.             break;
  917.         }
  918.         NEXT_KEY_LINE();
  919.         }
  920.         linetypeOffset = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
  921.         while (cntrs) {
  922.         if (label_contours && cntrs->isNewLevel) {
  923.             (*t->linetype) (linetypeOffset++);
  924.             if (key) {
  925.  
  926. #ifndef LITE
  927.             if (hidden3d)
  928.                 hidden_line_type_below = hidden_line_type_above = linetypeOffset - 1;
  929. #endif /* not LITE */
  930.  
  931.             key_text(xl, yl, cntrs->label);
  932.  
  933.             switch (this_plot->plot_style) {
  934.             case IMPULSES:
  935.             case LINES:
  936.             case LINESPOINTS:
  937.             case BOXES:    /* HBB: these should be treated as well... */
  938.             case STEPS:
  939.             case FSTEPS:
  940.             case HISTEPS:
  941.                 key_sample_line(xl, yl);
  942.                 break;
  943.             case YERRORBARS:    /* ignored; treat like points */
  944.             case XERRORBARS:    /* ignored; treat like points */
  945.             case XYERRORBARS:    /* ignored; treat like points */
  946.             case BOXERROR:        /* HBB: treat these likewise */
  947.             case BOXXYERROR:
  948.             case CANDLESTICKS:    /* HBB: dito */
  949.             case FINANCEBARS:
  950.             case VECTOR:
  951.             case POINTSTYLE:
  952.                 key_sample_point(xl, yl, this_plot->lp_properties.p_type);
  953.                 break;
  954.             case DOTS:
  955.                 key_sample_point(xl, yl, -1);
  956.                 break;
  957.             }    /* switch */
  958.  
  959.             NEXT_KEY_LINE();
  960.  
  961.             }        /* key */
  962.         }        /* label_contours */
  963.         /* now draw the contour */
  964.         switch (this_plot->plot_style) {
  965.         case IMPULSES:
  966.         case BOXES:    /* HBB: this should also be treated somehow */
  967.             cntr3d_impulses(cntrs, this_plot);
  968.             break;
  969.         case LINES:
  970.         case STEPS:    /* HBB: these should also be handled, I think */
  971.         case FSTEPS:
  972.         case HISTEPS:
  973.             cntr3d_lines(cntrs);
  974.             break;
  975.         case YERRORBARS:    /* ignored; treat like points */
  976.         case XERRORBARS:    /* ignored; treat like points */
  977.         case XYERRORBARS:    /* ignored; treat like points */
  978.         case BOXERROR:    /* HBB: ignore these too... */
  979.         case BOXXYERROR:
  980.         case CANDLESTICKS:    /* HBB: dito */
  981.         case FINANCEBARS:
  982.         case VECTOR:
  983.         case POINTSTYLE:
  984.             cntr3d_points(cntrs, this_plot);
  985.             break;
  986.         case LINESPOINTS:
  987.             cntr3d_lines(cntrs);
  988.             cntr3d_points(cntrs, this_plot);
  989.             break;
  990.         case DOTS:
  991.             cntr3d_dots(cntrs);
  992.             break;
  993.         }        /*switch */
  994.  
  995.         cntrs = cntrs->next;
  996.         }            /* loop over contours */
  997.     }            /* draw contours */
  998.     }                /* loop over surfaces */
  999.  
  1000.     draw_bottom_grid(plots, pcount);
  1001.  
  1002.     term_end_plot();
  1003.  
  1004. #ifndef LITE
  1005.     if (hidden3d && draw_surface) {
  1006.     term_hidden_line_removal();
  1007.     hidden_active = FALSE;
  1008.     }
  1009. #endif /* not LITE */
  1010.  
  1011. }
  1012.  
  1013. /* plot3d_impulses:
  1014.  * Plot the surfaces in IMPULSES style
  1015.  */
  1016. static void plot3d_impulses(plot)
  1017. struct surface_points *plot;
  1018. {
  1019.     int i;            /* point index */
  1020.     unsigned int x, y, x0, y0;    /* point in terminal coordinates */
  1021.     struct iso_curve *icrvs = plot->iso_crvs;
  1022.  
  1023.     while (icrvs) {
  1024.     struct coordinate GPHUGE *points = icrvs->points;
  1025.  
  1026.     for (i = 0; i < icrvs->p_count; i++) {
  1027.         switch (points[i].type) {
  1028.         case INRANGE:
  1029.         {
  1030.             map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1031.  
  1032.             if (inrange(0.0, min3d_z, max3d_z)) {
  1033.             map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
  1034.             } else if (inrange(min3d_z, 0.0, points[i].z)) {
  1035.             map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
  1036.             } else {
  1037.             map3d_xy(points[i].x, points[i].y, max3d_z, &x0, &y0);
  1038.             }
  1039.  
  1040.             clip_move(x0, y0);
  1041.             clip_vector(x, y);
  1042.  
  1043.             break;
  1044.         }
  1045.         case OUTRANGE:
  1046.         {
  1047.             if (!inrange(points[i].x, x_min3d, x_max3d) ||
  1048.             !inrange(points[i].y, y_min3d, y_max3d))
  1049.             break;
  1050.  
  1051.             if (inrange(0.0, min3d_z, max3d_z)) {
  1052.             /* zero point is INRANGE */
  1053.             map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
  1054.  
  1055.             /* must cross z = min3d_z or max3d_z limits */
  1056.             if (inrange(min3d_z, 0.0, points[i].z) &&
  1057.                 min3d_z != 0.0 && min3d_z != points[i].z) {
  1058.                 map3d_xy(points[i].x, points[i].y, min3d_z, &x, &y);
  1059.             } else {
  1060.                 map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
  1061.             }
  1062.             } else {
  1063.             /* zero point is also OUTRANGE */
  1064.             if (inrange(min3d_z, 0.0, points[i].z) &&
  1065.                 inrange(max3d_z, 0.0, points[i].z)) {
  1066.                 /* crosses z = min3d_z or max3d_z limits */
  1067.                 map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
  1068.                 map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
  1069.             } else {
  1070.                 /* doesn't cross z = min3d_z or max3d_z limits */
  1071.                 break;
  1072.             }
  1073.             }
  1074.  
  1075.             clip_move(x0, y0);
  1076.             clip_vector(x, y);
  1077.  
  1078.             break;
  1079.         }
  1080.         default:        /* just a safety */
  1081.         case UNDEFINED:{
  1082.             break;
  1083.         }
  1084.         }
  1085.     }
  1086.  
  1087.     icrvs = icrvs->next;
  1088.     }
  1089. }
  1090.  
  1091. /* plot3d_lines:
  1092.  * Plot the surfaces in LINES style
  1093.  */
  1094. /* We want to always draw the lines in the same direction, otherwise when
  1095.    we draw an adjacent box we might get the line drawn a little differently
  1096.    and we get splotches.  */
  1097.  
  1098. static void plot3d_lines(plot)
  1099. struct surface_points *plot;
  1100. {
  1101.     int i;
  1102.     unsigned int x, y, x0, y0;    /* point in terminal coordinates */
  1103.     double clip_x, clip_y, clip_z;
  1104.     struct iso_curve *icrvs = plot->iso_crvs;
  1105.     struct coordinate GPHUGE *points;
  1106.     enum coord_type prev = UNDEFINED;
  1107.     double lx[2], ly[2], lz[2];    /* two edge points */
  1108.  
  1109. #ifndef LITE
  1110. /* These are handled elsewhere.  */
  1111.     if (plot->has_grid_topology && hidden3d)
  1112.     return;
  1113. #endif /* not LITE */
  1114.  
  1115.     while (icrvs) {
  1116.     prev = UNDEFINED;    /* type of previous plot */
  1117.  
  1118.     for (i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
  1119.         switch (points[i].type) {
  1120.         case INRANGE:{
  1121.             map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1122.  
  1123.             if (prev == INRANGE) {
  1124.             clip_vector(x, y);
  1125.             } else {
  1126.             if (prev == OUTRANGE) {
  1127.                 /* from outrange to inrange */
  1128.                 if (!clip_lines1) {
  1129.                 clip_move(x, y);
  1130.                 } else {
  1131.                 /*
  1132.                  * Calculate intersection point and draw
  1133.                  * vector from there
  1134.                  */
  1135.                 edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
  1136.  
  1137.                 map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
  1138.  
  1139.                 clip_move(x0, y0);
  1140.                 clip_vector(x, y);
  1141.                 }
  1142.             } else {
  1143.                 clip_move(x, y);
  1144.             }
  1145.             }
  1146.  
  1147.             break;
  1148.         }
  1149.         case OUTRANGE:{
  1150.             if (prev == INRANGE) {
  1151.             /* from inrange to outrange */
  1152.             if (clip_lines1) {
  1153.                 /*
  1154.                  * Calculate intersection point and draw
  1155.                  * vector to it
  1156.                  */
  1157.  
  1158.                 edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
  1159.  
  1160.                 map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
  1161.  
  1162.                 clip_vector(x0, y0);
  1163.             }
  1164.             } else if (prev == OUTRANGE) {
  1165.             /* from outrange to outrange */
  1166.             if (clip_lines2) {
  1167.                 /*
  1168.                  * Calculate the two 3D intersection points
  1169.                  * if present
  1170.                  */
  1171.                 if (two_edge3d_intersect(points, i, lx, ly, lz)) {
  1172.  
  1173.                 map3d_xy(lx[0], ly[0], lz[0], &x, &y);
  1174.  
  1175.                 map3d_xy(lx[1], ly[1], lz[1], &x0, &y0);
  1176.  
  1177.                 clip_move(x, y);
  1178.                 clip_vector(x0, y0);
  1179.                 }
  1180.             }
  1181.             }
  1182.             break;
  1183.         }
  1184.         case UNDEFINED:{
  1185.             break;
  1186.         default:
  1187.             graph_error("Unknown point type in plot3d_lines");
  1188.         }
  1189.         }
  1190.  
  1191.         prev = points[i].type;
  1192.     }
  1193.  
  1194.     icrvs = icrvs->next;
  1195.     }
  1196. }
  1197.  
  1198. /* plot3d_points:
  1199.  * Plot the surfaces in POINTSTYLE style
  1200.  */
  1201. static void plot3d_points(plot)
  1202. struct surface_points *plot;
  1203. {
  1204.     int i;
  1205.     unsigned int x, y;
  1206.     struct termentry *t = term;
  1207.     struct iso_curve *icrvs = plot->iso_crvs;
  1208.  
  1209.     while (icrvs) {
  1210.     struct coordinate GPHUGE *points = icrvs->points;
  1211.  
  1212.     for (i = 0; i < icrvs->p_count; i++) {
  1213.         if (points[i].type == INRANGE) {
  1214.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1215.  
  1216.         if (!clip_point(x, y))
  1217.             (*t->point) (x, y, plot->lp_properties.p_type);
  1218.         }
  1219.     }
  1220.  
  1221.     icrvs = icrvs->next;
  1222.     }
  1223. }
  1224.  
  1225. /* plot3d_dots:
  1226.  * Plot the surfaces in DOTS style
  1227.  */
  1228. static void plot3d_dots(plot)
  1229. struct surface_points *plot;
  1230. {
  1231.     int i;
  1232.     struct termentry *t = term;
  1233.     struct iso_curve *icrvs = plot->iso_crvs;
  1234.  
  1235.     while (icrvs) {
  1236.     struct coordinate GPHUGE *points = icrvs->points;
  1237.  
  1238.     for (i = 0; i < icrvs->p_count; i++) {
  1239.         if (points[i].type == INRANGE) {
  1240.         unsigned int x, y;
  1241.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1242.  
  1243.         if (!clip_point(x, y))
  1244.             (*t->point) (x, y, -1);
  1245.         }
  1246.     }
  1247.  
  1248.     icrvs = icrvs->next;
  1249.     }
  1250. }
  1251.  
  1252. /* cntr3d_impulses:
  1253.  * Plot a surface contour in IMPULSES style
  1254.  */
  1255. static void cntr3d_impulses(cntr, plot)
  1256. struct gnuplot_contours *cntr;
  1257. struct surface_points *plot;
  1258. {
  1259.     int i;            /* point index */
  1260.     unsigned int x, y, x0, y0;    /* point in terminal coordinates */
  1261.  
  1262.     if (draw_contour & CONTOUR_SRF) {
  1263.     for (i = 0; i < cntr->num_pts; i++) {
  1264.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1265.              &x, &y);
  1266.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1267.              &x0, &y0);
  1268.  
  1269.         clip_move(x0, y0);
  1270.         clip_vector(x, y);
  1271.     }
  1272.     } else {
  1273.     /* Must be on base grid, so do points. */
  1274.     cntr3d_points(cntr, plot);
  1275.     }
  1276. }
  1277.  
  1278. /* cntr3d_lines:
  1279.  * Plot a surface contour in LINES style
  1280.  */
  1281. static void cntr3d_lines(cntr)
  1282. struct gnuplot_contours *cntr;
  1283. {
  1284.     int i;            /* point index */
  1285.     unsigned int x, y;        /* point in terminal coordinates */
  1286.  
  1287.     if (draw_contour & CONTOUR_SRF) {
  1288.     for (i = 0; i < cntr->num_pts; i++) {
  1289.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1290.              &x, &y);
  1291.  
  1292.         if (i > 0) {
  1293.         clip_vector(x, y);
  1294.         if (i == 1)
  1295.             suppressMove = TRUE;
  1296.         } else {
  1297.         clip_move(x, y);
  1298.         }
  1299.     }
  1300.     }
  1301.     /* beginning a new contour level, so moveto() required */
  1302.     suppressMove = FALSE;
  1303.  
  1304.     if (draw_contour & CONTOUR_BASE) {
  1305.     for (i = 0; i < cntr->num_pts; i++) {
  1306.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1307.              &x, &y);
  1308.  
  1309.         if (i > 0) {
  1310.         clip_vector(x, y);
  1311.         if (i == 1)
  1312.             suppressMove = TRUE;
  1313.         } else {
  1314.         clip_move(x, y);
  1315.         }
  1316.     }
  1317.     }
  1318.     /* beginning a new contour level, so moveto() required */
  1319.     suppressMove = FALSE;
  1320. }
  1321.  
  1322. /* cntr3d_points:
  1323.  * Plot a surface contour in POINTSTYLE style
  1324.  */
  1325. static void cntr3d_points(cntr, plot)
  1326. struct gnuplot_contours *cntr;
  1327. struct surface_points *plot;
  1328. {
  1329.     int i;
  1330.     unsigned int x, y;
  1331.     struct termentry *t = term;
  1332.  
  1333.     if (draw_contour & CONTOUR_SRF) {
  1334.     for (i = 0; i < cntr->num_pts; i++) {
  1335.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z, &x, &y);
  1336.  
  1337.         if (!clip_point(x, y))
  1338.         (*t->point) (x, y, plot->lp_properties.p_type);
  1339.     }
  1340.     }
  1341.     if (draw_contour & CONTOUR_BASE) {
  1342.     for (i = 0; i < cntr->num_pts; i++) {
  1343.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1344.              &x, &y);
  1345.  
  1346.         if (!clip_point(x, y))
  1347.         (*t->point) (x, y, plot->lp_properties.p_type);
  1348.     }
  1349.     }
  1350. }
  1351.  
  1352. /* cntr3d_dots:
  1353.  * Plot a surface contour in DOTS style
  1354.  */
  1355. static void cntr3d_dots(cntr)
  1356. struct gnuplot_contours *cntr;
  1357. {
  1358.     int i;
  1359.     unsigned int x, y;
  1360.     struct termentry *t = term;
  1361.  
  1362.     if (draw_contour & CONTOUR_SRF) {
  1363.     for (i = 0; i < cntr->num_pts; i++) {
  1364.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z, &x, &y);
  1365.  
  1366.         if (!clip_point(x, y))
  1367.         (*t->point) (x, y, -1);
  1368.     }
  1369.     }
  1370.     if (draw_contour & CONTOUR_BASE) {
  1371.     for (i = 0; i < cntr->num_pts; i++) {
  1372.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1373.              &x, &y);
  1374.  
  1375.         if (!clip_point(x, y))
  1376.         (*t->point) (x, y, -1);
  1377.     }
  1378.     }
  1379. }
  1380.  
  1381.  
  1382.  
  1383. /* map xmin | xmax to 0 | 1 and same for y
  1384.  * 0.1 avoids any rounding errors
  1385.  */
  1386. #define MAP_HEIGHT_X(x) ( (int) (((x)-x_min3d)/(x_max3d-x_min3d)+0.1) )
  1387. #define MAP_HEIGHT_Y(y) ( (int) (((y)-y_min3d)/(y_max3d-y_min3d)+0.1) )
  1388.  
  1389. /* if point is at corner, update height[][] and depth[][]
  1390.  * we are still assuming that extremes of surfaces are at corners,
  1391.  * but we are not assuming order of corners
  1392.  */
  1393. static void check_corner_height(p, height, depth)
  1394. struct coordinate GPHUGE *p;
  1395. double height[2][2];
  1396. double depth[2][2];
  1397. {
  1398.     if (p->type != INRANGE)
  1399.     return;
  1400.     if ((fabs(p->x - x_min3d) < zero || fabs(p->x - x_max3d) < zero) &&
  1401.     (fabs(p->y - y_min3d) < zero || fabs(p->y - y_max3d) < zero)) {
  1402.     unsigned int x = MAP_HEIGHT_X(p->x);
  1403.     unsigned int y = MAP_HEIGHT_Y(p->y);
  1404.     if (height[x][y] < p->z)
  1405.         height[x][y] = p->z;
  1406.     if (depth[x][y] > p->z)
  1407.         depth[x][y] = p->z;
  1408.     }
  1409. }
  1410.  
  1411.  
  1412. /* Draw the bottom grid that hold the tic marks for 3d surface. */
  1413. static void draw_bottom_grid(plot, plot_num)
  1414. struct surface_points *plot;
  1415. int plot_num;
  1416. {
  1417.     unsigned int x, y;        /* point in terminal coordinates */
  1418.     struct termentry *t = term;
  1419.     char ss[MAX_LINE_LEN+1];
  1420.  
  1421.     /* work out where the axes and tics are drawn */
  1422.  
  1423.     {
  1424.     int quadrant = surface_rot_z / 90;
  1425.     if ((quadrant + 1) & 2) {
  1426.         zaxis_x = x_max3d;
  1427.         xaxis_y = y_max3d;
  1428.     } else {
  1429.         zaxis_x = x_min3d;
  1430.         xaxis_y = y_min3d;
  1431.     }
  1432.  
  1433.     if (quadrant & 2) {
  1434.         zaxis_y = y_max3d;
  1435.         yaxis_x = x_min3d;
  1436.     } else {
  1437.         zaxis_y = y_min3d;
  1438.         yaxis_x = x_max3d;
  1439.     }
  1440.  
  1441.     if (surface_rot_x > 90) {
  1442.         /* labels on the back axes */
  1443.         back_x = yaxis_x = x_min3d + x_max3d - yaxis_x;
  1444.         back_y = xaxis_y = y_min3d + y_max3d - xaxis_y;
  1445.     } else {
  1446.         back_x = x_min3d + x_max3d - yaxis_x;
  1447.         back_y = y_min3d + y_max3d - xaxis_y;
  1448.     }
  1449.     }
  1450.  
  1451.     if (draw_border) {
  1452.     unsigned int bl_x, bl_y;    /* bottom left */
  1453.     unsigned int bb_x, bb_y;    /* bottom back */
  1454.     unsigned int br_x, br_y;    /* bottom right */
  1455.     unsigned int bf_x, bf_y;    /* bottom front */
  1456.  
  1457. #ifndef LITE
  1458.     int save_update = hidden_no_update;
  1459.     hidden_no_update = TRUE;
  1460. #endif /* LITE */
  1461.  
  1462.     /* Here is the one and only call to this function. */
  1463.     setlinestyle(border_lp);
  1464.  
  1465.     map3d_xy(zaxis_x, zaxis_y, base_z, &bl_x, &bl_y);
  1466.     map3d_xy(back_x, back_y, base_z, &bb_x, &bb_y);
  1467.     map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, base_z, &br_x, &br_y);
  1468.     map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, base_z, &bf_x, &bf_y);
  1469.  
  1470.     /* border around base */
  1471.     {
  1472.         int save = hidden_active;
  1473.         hidden_active = FALSE;    /* this is in front */
  1474.         if (draw_border & 4)
  1475.         draw_clip_line(br_x, br_y, bf_x, bf_y);
  1476.         if (draw_border & 1)
  1477.         draw_clip_line(bl_x, bl_y, bf_x, bf_y);
  1478.         hidden_active = save;
  1479.     }
  1480.     if (draw_border & 2)
  1481.         draw_clip_line(bl_x, bl_y, bb_x, bb_y);
  1482.     if (draw_border & 8)
  1483.         draw_clip_line(br_x, br_y, bb_x, bb_y);
  1484.  
  1485.     if (draw_surface || (draw_contour & CONTOUR_SRF)) {
  1486.         int save = hidden_active;
  1487.         /* map the 8 corners to screen */
  1488.         unsigned int fl_x, fl_y;    /* floor left */
  1489.         unsigned int fb_x, fb_y;    /* floor back */
  1490.         unsigned int fr_x, fr_y;    /* floor right */
  1491.         unsigned int ff_x, ff_y;    /* floor front */
  1492.  
  1493.         unsigned int tl_x, tl_y;    /* top left */
  1494.         unsigned int tb_x, tb_y;    /* top back */
  1495.         unsigned int tr_x, tr_y;    /* top right */
  1496.         unsigned int tf_x, tf_y;    /* top front */
  1497.  
  1498.         map3d_xy(zaxis_x, zaxis_y, floor_z, &fl_x, &fl_y);
  1499.         map3d_xy(back_x, back_y, floor_z, &fb_x, &fb_y);
  1500.         map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, floor_z, &fr_x, &fr_y);
  1501.         map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, floor_z, &ff_x, &ff_y);
  1502.  
  1503.         map3d_xy(zaxis_x, zaxis_y, ceiling_z, &tl_x, &tl_y);
  1504.         map3d_xy(back_x, back_y, ceiling_z, &tb_x, &tb_y);
  1505.         map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, ceiling_z, &tr_x, &tr_y);
  1506.         map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, ceiling_z, &tf_x, &tf_y);
  1507.  
  1508.         /* vertical lines, to surface or to very top */
  1509.         if ((draw_border & 0xf0) == 0xf0) {
  1510.         /* all four verticals drawn - save some time */
  1511.         draw_clip_line(fl_x, fl_y, tl_x, tl_y);
  1512.         draw_clip_line(fb_x, fb_y, tb_x, tb_y);
  1513.         draw_clip_line(fr_x, fr_y, tr_x, tr_y);
  1514.         hidden_active = FALSE;    /* this is in front */
  1515.         draw_clip_line(ff_x, ff_y, tf_x, tf_y);
  1516.         hidden_active = save;
  1517.         } else {
  1518.         /* search surfaces for heights at corners */
  1519.         double height[2][2];
  1520.         double depth[2][2];
  1521.         unsigned int zaxis_i = MAP_HEIGHT_X(zaxis_x);
  1522.         unsigned int zaxis_j = MAP_HEIGHT_Y(zaxis_y);
  1523.         unsigned int back_i = MAP_HEIGHT_X(back_x);
  1524.     /* HBB: why isn't back_j unsigned ??? */
  1525.         int back_j = MAP_HEIGHT_Y(back_y);
  1526.  
  1527.         height[0][0] = height[0][1] = height[1][0] = height[1][1] = base_z;
  1528.         depth[0][0] = depth[0][1] = depth[1][0] = depth[1][1] = base_z;
  1529.  
  1530.         for (; --plot_num >= 0; plot = plot->next_sp) {
  1531.             struct iso_curve *curve = plot->iso_crvs;
  1532.             int count = curve->p_count;
  1533.             int iso;
  1534.             if (plot->plot_type == DATA3D) {
  1535.             if (!plot->has_grid_topology)
  1536.                 continue;
  1537.             iso = plot->num_iso_read;
  1538.             } else
  1539.             iso = iso_samples_2;
  1540.  
  1541.             check_corner_height(curve->points, height, depth);
  1542.             check_corner_height(curve->points + count - 1, height, depth);
  1543.             while (--iso)
  1544.             curve = curve->next;
  1545.             check_corner_height(curve->points, height, depth);
  1546.             check_corner_height(curve->points + count - 1, height, depth);
  1547.         }
  1548.  
  1549. #define VERTICAL(mask,x,y,i,j,bx,by,tx,ty) \
  1550.  if (draw_border&mask) \
  1551.   draw_clip_line(bx,by,tx,ty);\
  1552. else if (height[i][j] != depth[i][j]) \
  1553. { unsigned int a0,b0, a1, b1; \
  1554.   map3d_xy(x,y,depth[i][j],&a0,&b0); \
  1555.   map3d_xy(x,y,height[i][j],&a1,&b1); \
  1556.   draw_clip_line(a0,b0,a1,b1); \
  1557. }
  1558.  
  1559.         VERTICAL(16,zaxis_x,zaxis_y,zaxis_i,zaxis_j,fl_x,fl_y,tl_x,tl_y);
  1560.         VERTICAL(32,back_x,back_y,back_i,back_j,fb_x,fb_y,tb_x,tb_y);
  1561.         VERTICAL(64,x_min3d+x_max3d-zaxis_x,y_min3d+y_max3d-zaxis_y,1-zaxis_i,1-zaxis_j,fr_x,fr_y,tr_x,tr_y);
  1562.         hidden_active = FALSE;
  1563.         VERTICAL(128,x_min3d+x_max3d-back_x,y_min3d+y_max3d-back_y,1-back_i,1-back_j,ff_x,ff_y,tf_x,tf_y);
  1564.             hidden_active = save;
  1565.         }
  1566.  
  1567.         /* now border lines on top */
  1568.         if (draw_border & 256)
  1569.         draw_clip_line(tl_x, tl_y, tb_x, tb_y);
  1570.         if (draw_border & 512)
  1571.         draw_clip_line(tr_x, tr_y, tb_x, tb_y);
  1572.         /* these lines are in front of surface (?) */
  1573.         hidden_active = FALSE;
  1574.         if (draw_border & 1024)
  1575.         draw_clip_line(tl_x, tl_y, tf_x, tf_y);
  1576.         if (draw_border & 2048)
  1577.         draw_clip_line(tr_x, tr_y, tf_x, tf_y);
  1578.         hidden_active = save;
  1579.     }
  1580.  
  1581. #ifndef LITE
  1582.     hidden_no_update = save_update;
  1583. #endif /* LITE */
  1584.  
  1585.     }
  1586.     if (xtics || *xlabel.text) {
  1587.     unsigned int x0, y0, x1, y1;
  1588.     double mid_x = (x_max3d + x_min3d) / 2;
  1589.     double len;
  1590.     map3d_xy(mid_x, xaxis_y, base_z, &x0, &y0);
  1591.     map3d_xy(mid_x, y_min3d + y_max3d - xaxis_y, base_z, &x1, &y1);
  1592.     {            /* take care over unsigned quantities */
  1593.         int dx = x1 - x0;
  1594.         int dy = y1 - y0;
  1595.         /* HBB 980309: 16bit strikes back: */
  1596.         len = sqrt(((double) dx) * dx + ((double) dy) * dy);
  1597.         if (len != 0) {
  1598.         tic_unitx = dx / len;
  1599.         tic_unity = dy / len;
  1600.         } else {
  1601.         tic_unitx = tic_unity = 0;
  1602.         }
  1603.     }
  1604.  
  1605.     if (xtics) {
  1606.         gen_tics(FIRST_X_AXIS, &xticdef,
  1607.              work_grid.l_type & (GRID_X | GRID_MX),
  1608.              mxtics, mxtfreq, xtick_callback);
  1609.     }
  1610.     if (*xlabel.text) {
  1611.         /* label at xaxis_y + 1/4 of (xaxis_y-other_y) */
  1612.         double step = (2 * xaxis_y - y_max3d - y_min3d) / 4;
  1613.         map3d_xy(mid_x, xaxis_y + step, base_z, &x1, &y1);
  1614.         x1 += xlabel.xoffset * t->h_char;
  1615.         y1 += xlabel.yoffset * t->v_char;
  1616.         if (!tic_in) {
  1617.         x1 -= tic_unitx * ticscale * (t->h_tic);
  1618.         y1 -= tic_unity * ticscale * (t->v_tic);
  1619.         }
  1620.         /* write_multiline mods it */
  1621.         safe_strncpy(ss, xlabel.text, sizeof(ss));
  1622.         write_multiline(x1, y1, ss, CENTRE, JUST_TOP, 0, xlabel.font);
  1623.     }
  1624.     }
  1625.     if (ytics || *ylabel.text) {
  1626.     unsigned int x0, y0, x1, y1;
  1627.     double mid_y = (y_max3d + y_min3d) / 2;
  1628.     double len;
  1629.     map3d_xy(yaxis_x, mid_y, base_z, &x0, &y0);
  1630.     map3d_xy(x_min3d + x_max3d - yaxis_x, mid_y, base_z, &x1, &y1);
  1631.     {            /* take care over unsigned quantities */
  1632.         int dx = x1 - x0;
  1633.         int dy = y1 - y0;
  1634.         /* HBB 980309: 16 Bits strike again: */
  1635.         len = sqrt(((double) dx) * dx + ((double) dy) * dy);
  1636.         if (len != 0) {
  1637.         tic_unitx = dx / len;
  1638.         tic_unity = dy / len;
  1639.         } else {
  1640.         tic_unitx = tic_unity = 0;
  1641.         }
  1642.     }
  1643.     if (ytics) {
  1644.         gen_tics(FIRST_Y_AXIS, &yticdef,
  1645.              work_grid.l_type & (GRID_Y | GRID_MY),
  1646.              mytics, mytfreq, ytick_callback);
  1647.     }
  1648.     if (*ylabel.text) {
  1649.         double step = (x_max3d + x_min3d - 2 * yaxis_x) / 4;
  1650.         map3d_xy(yaxis_x - step, mid_y, base_z, &x1, &y1);
  1651.         x1 += ylabel.xoffset * t->h_char;
  1652.         y1 += ylabel.yoffset * t->v_char;
  1653.         if (!tic_in) {
  1654.         x1 -= tic_unitx * ticscale * (t->h_tic);
  1655.         y1 -= tic_unity * ticscale * (t->v_tic);
  1656.         }
  1657.         /* write_multiline mods it */
  1658.         safe_strncpy(ss, ylabel.text, sizeof(ss));
  1659.         write_multiline(x1, y1, ss, CENTRE, JUST_TOP, 0, ylabel.font);
  1660.     }
  1661.     }
  1662.     /* do z tics */
  1663.  
  1664.     if (ztics && (draw_surface || (draw_contour & CONTOUR_SRF))) {
  1665.     gen_tics(FIRST_Z_AXIS, &zticdef, work_grid.l_type & (GRID_Z | GRID_MZ),
  1666.          mztics, mztfreq, ztick_callback);
  1667.     }
  1668.     if ((xzeroaxis.l_type >= -2) && !is_log_y && inrange(0, y_min3d, y_max3d)) {
  1669.     unsigned int x, y, x1, y1;
  1670.     term_apply_lp_properties(&xzeroaxis);
  1671.     map3d_xy(0.0, y_min3d, base_z, &x, &y);        /* line through x=0 */
  1672.     map3d_xy(0.0, y_max3d, base_z, &x1, &y1);
  1673.     draw_clip_line(x, y, x1, y1);
  1674.     }
  1675.     if ((yzeroaxis.l_type >= -2) && !is_log_x && inrange(0, x_min3d, x_max3d)) {
  1676.     unsigned int x, y, x1, y1;
  1677.     term_apply_lp_properties(&yzeroaxis);
  1678.     map3d_xy(x_min3d, 0.0, base_z, &x, &y);        /* line through y=0 */
  1679.     map3d_xy(x_max3d, 0.0, base_z, &x1, &y1);
  1680.     draw_clip_line(x, y, x1, y1);
  1681.     }
  1682.     /* PLACE ZLABEL - along the middle grid Z axis - eh ? */
  1683.     if (*zlabel.text && (draw_surface || (draw_contour & CONTOUR_SRF))) {
  1684.     map3d_xy(zaxis_x, zaxis_y, z_max3d + (z_max3d - base_z) / 4, &x, &y);
  1685.  
  1686.     x += zlabel.xoffset * t->h_char;
  1687.     y += zlabel.yoffset * t->v_char;
  1688.  
  1689.     safe_strncpy(ss, zlabel.text, sizeof(ss));
  1690.     write_multiline(x, y, ss, CENTRE, CENTRE, 0, zlabel.font);
  1691.  
  1692.     }
  1693. }
  1694.  
  1695.  
  1696. static void xtick_callback(axis, place, text, grid)
  1697. int axis;
  1698. double place;
  1699. char *text;
  1700. struct lp_style_type grid;    /* linetype or -2 for none */
  1701. {
  1702.     unsigned int x, y, x1, y1;
  1703.     double scale = (text ? ticscale : miniticscale);
  1704.     int dirn = tic_in ? 1 : -1;
  1705.     register struct termentry *t = term;
  1706.  
  1707.     map3d_xy(place, xaxis_y, base_z, &x, &y);
  1708.     if (grid.l_type > -2) {
  1709.     term_apply_lp_properties(&grid);
  1710.     /* to save mapping twice, map non-axis y */
  1711.     map3d_xy(place, y_min3d + y_max3d - xaxis_y, base_z, &x1, &y1);
  1712.     draw_clip_line(x, y, x1, y1);
  1713.     term_apply_lp_properties(&border_lp);
  1714.     }
  1715.     if (xtics & TICS_ON_AXIS) {
  1716.     map3d_xy(place, (y_min3d + y_max3d) / 2, base_z, &x, &y);
  1717.     }
  1718.     x1 = x + tic_unitx * scale * (t->h_tic) * dirn;
  1719.     y1 = y + tic_unity * scale * (t->v_tic) * dirn;
  1720.     draw_clip_line(x, y, x1, y1);
  1721.     if (text) {
  1722.     int just;
  1723.     if (tic_unitx < -0.9)
  1724.         just = LEFT;
  1725.     else if (tic_unitx < 0.9)
  1726.         just = CENTRE;
  1727.     else
  1728.         just = RIGHT;
  1729. #if 1
  1730. /* HBB 970729: let's see if the 'tic labels collide with axes' problem
  1731.  * may be fixed this way: */
  1732.     x1 = x - tic_unitx * (t->h_char) * 1;
  1733.     y1 = y - tic_unity * (t->v_char) * 1;
  1734. #else
  1735.     x1 = x - tic_unitx * (t->h_tic) * 2;
  1736.     y1 = y - tic_unity * (t->v_tic) * 2;
  1737. #endif
  1738.     if (!tic_in) {
  1739.         x1 -= tic_unitx * (t->h_tic) * ticscale;
  1740.         y1 -= tic_unity * (t->v_tic) * ticscale;
  1741.     }
  1742.     clip_put_text_just(x1, y1, text, just);
  1743.     }
  1744.     if (xtics & TICS_MIRROR) {
  1745.     map3d_xy(place, y_min3d + y_max3d - xaxis_y, base_z, &x, &y);
  1746.     x1 = x - tic_unitx * scale * (t->h_tic) * dirn;
  1747.     y1 = y - tic_unity * scale * (t->v_tic) * dirn;
  1748.     draw_clip_line(x, y, x1, y1);
  1749.     }
  1750. }
  1751.  
  1752. static void ytick_callback(axis, place, text, grid)
  1753. int axis;
  1754. double place;
  1755. char *text;
  1756. struct lp_style_type grid;
  1757. {
  1758.     unsigned int x, y, x1, y1;
  1759.     double scale = (text ? ticscale : miniticscale);
  1760.     int dirn = tic_in ? 1 : -1;
  1761.     register struct termentry *t = term;
  1762.  
  1763.     map3d_xy(yaxis_x, place, base_z, &x, &y);
  1764.     if (grid.l_type > -2) {
  1765.     term_apply_lp_properties(&grid);
  1766.     map3d_xy(x_min3d + x_max3d - yaxis_x, place, base_z, &x1, &y1);
  1767.     draw_clip_line(x, y, x1, y1);
  1768.     term_apply_lp_properties(&border_lp);
  1769.     }
  1770.     if (ytics & TICS_ON_AXIS) {
  1771.     map3d_xy((x_min3d + x_max3d) / 2, place, base_z, &x, &y);
  1772.     }
  1773.     x1 = x + tic_unitx * scale * dirn * (t->h_tic);
  1774.     y1 = y + tic_unity * scale * dirn * (t->v_tic);
  1775.     draw_clip_line(x, y, x1, y1);
  1776.     if (text) {
  1777.     int just;
  1778.     if (tic_unitx < -0.9)
  1779.         just = LEFT;
  1780.     else if (tic_unitx < 0.9)
  1781.         just = CENTRE;
  1782.     else
  1783.         just = RIGHT;
  1784. #if 1
  1785.     /* HBB 970729: same as above in xtics_callback */
  1786.     x1 = x - tic_unitx * (t->h_char) * 1;
  1787.     y1 = y - tic_unity * (t->v_char) * 1;
  1788. #else
  1789.     x1 = x - tic_unitx * (t->h_tic) * 2;
  1790.     y1 = y - tic_unity * (t->v_tic) * 2;
  1791. #endif
  1792.     if (!tic_in) {
  1793.         x1 -= tic_unitx * (t->h_tic) * ticscale;
  1794.         y1 -= tic_unity * (t->v_tic) * ticscale;
  1795.     }
  1796.     clip_put_text_just(x1, y1, text, just);
  1797.     }
  1798.     if (ytics & TICS_MIRROR) {
  1799.     map3d_xy(x_min3d + x_max3d - yaxis_x, place, base_z, &x, &y);
  1800.     x1 = x - tic_unitx * scale * (t->h_tic) * dirn;
  1801.     y1 = y - tic_unity * scale * (t->v_tic) * dirn;
  1802.     draw_clip_line(x, y, x1, y1);
  1803.     }
  1804. }
  1805.  
  1806. static void ztick_callback(axis, place, text, grid)
  1807. int axis;
  1808. double place;
  1809. char *text;
  1810. struct lp_style_type grid;
  1811. {
  1812. /* HBB: inserted some ()'s to shut up gcc -Wall, here and below */
  1813.     int len = (text ? ticscale : miniticscale) * (tic_in ? 1 : -1) * (term->h_tic);
  1814.     unsigned int x, y;
  1815.  
  1816.     if (grid.l_type > -2) {
  1817.     unsigned int x1, y1, x2, y2, x3, y3;
  1818.     double other_x = x_min3d + x_max3d - zaxis_x;
  1819.     double other_y = y_min3d + y_max3d - zaxis_y;
  1820.     term_apply_lp_properties(&grid);
  1821.     map3d_xy(zaxis_x, zaxis_y, place, &x1, &y1);
  1822.     map3d_xy(back_x, back_y, place, &x2, &y2);
  1823.     map3d_xy(other_x, other_y, place, &x3, &y3);
  1824.     draw_clip_line(x1, y1, x2, y2);
  1825.     draw_clip_line(x2, y2, x3, y3);
  1826.     term_apply_lp_properties(&border_lp);
  1827.     }
  1828.     map3d_xy(zaxis_x, zaxis_y, place, &x, &y);
  1829.     draw_clip_line(x, y, x + len, y);
  1830.     if (text) {
  1831.     int x1 = x - (term->h_tic) * 2;
  1832.     if (!tic_in)
  1833.         x1 -= (term->h_tic) * ticscale;
  1834.     clip_put_text_just(x1, y, text, RIGHT);
  1835.     }
  1836.     if (ztics & TICS_MIRROR) {
  1837.     double other_x = x_min3d + x_max3d - zaxis_x;
  1838.     double other_y = y_min3d + y_max3d - zaxis_y;
  1839.     map3d_xy(other_x, other_y, place, &x, &y);
  1840.     draw_clip_line(x, y, x - len, y);
  1841.     }
  1842. }
  1843.  
  1844.  
  1845. static void map_position(pos, x, y, what)
  1846. struct position *pos;
  1847. unsigned int *x, *y;
  1848. char *what;
  1849. {
  1850.     double xpos = pos->x;
  1851.     double ypos = pos->y;
  1852.     double zpos = pos->z;
  1853.     int screens = 0;        /* need either 0 or 3 screen co-ordinates */
  1854.  
  1855.     switch (pos->scalex) {
  1856.     case first_axes:
  1857.     case second_axes:
  1858.     xpos = LogScale(xpos, is_log_x, log_base_log_x, what, "x");
  1859.     break;
  1860.     case graph:
  1861.     xpos = min_array[FIRST_X_AXIS] +
  1862.         xpos * (max_array[FIRST_X_AXIS] - min_array[FIRST_X_AXIS]);
  1863.     break;
  1864.     case screen:
  1865.     ++screens;
  1866.     }
  1867.  
  1868.     switch (pos->scaley) {
  1869.     case first_axes:
  1870.     case second_axes:
  1871.     ypos = LogScale(ypos, is_log_y, log_base_log_y, what, "y");
  1872.     break;
  1873.     case graph:
  1874.     ypos = min_array[FIRST_Y_AXIS] +
  1875.         ypos * (max_array[FIRST_Y_AXIS] - min_array[FIRST_Y_AXIS]);
  1876.     break;
  1877.     case screen:
  1878.     ++screens;
  1879.     }
  1880.  
  1881.     switch (pos->scalez) {
  1882.     case first_axes:
  1883.     case second_axes:
  1884.     zpos = LogScale(zpos, is_log_z, log_base_log_z, what, "z");
  1885.     break;
  1886.     case graph:
  1887.     zpos = min_array[FIRST_Z_AXIS] +
  1888.         zpos * (max_array[FIRST_Z_AXIS] - min_array[FIRST_Z_AXIS]);
  1889.     break;
  1890.     case screen:
  1891.     ++screens;
  1892.     }
  1893.  
  1894.     if (screens == 0) {
  1895.     map3d_xy(xpos, ypos, zpos, x, y);
  1896.     return;
  1897.     }
  1898.     if (screens != 3) {
  1899.     graph_error("Cannot mix screen co-ordinates with other types");
  1900.     } {
  1901.     register struct termentry *t = term;
  1902.     *x = pos->x * (t->xmax) + 0.5;
  1903.     *y = pos->y * (t->ymax) + 0.5;
  1904.     }
  1905.  
  1906.     return;
  1907. }
  1908.  
  1909.  
  1910. /*
  1911.  * these code blocks were moved to functions, to make the code simpler
  1912.  */
  1913.  
  1914. static void key_text(xl, yl, text)
  1915. int xl, yl;
  1916. char *text;
  1917. {
  1918.     if (key_just == JLEFT && key == -1) {
  1919.     (*term->justify_text) (LEFT);
  1920.     (*term->put_text) (xl + key_text_left, yl, text);
  1921.     } else {
  1922.     if ((*term->justify_text) (RIGHT)) {
  1923.         if (key == 1)
  1924.         clip_put_text(xl + key_text_right, yl, text);
  1925.         else
  1926.         (*term->put_text) (xl + key_text_right, yl, text);
  1927.     } else {
  1928.         int x = xl + key_text_right - (term->h_char) * strlen(text);
  1929.         if (key == 1) {
  1930.         if (i_inrange(x, xleft, xright))
  1931.             clip_put_text(x, yl, text);
  1932.         } else {
  1933.         (*term->put_text) (x, yl, text);
  1934.         }
  1935.     }
  1936.     }
  1937. }
  1938.  
  1939. static void key_sample_line(xl, yl)
  1940. int xl, yl;
  1941. {
  1942.     if (key == -1) {
  1943.     (*term->move) (xl + key_sample_left, yl);
  1944.     (*term->vector) (xl + key_sample_right, yl);
  1945.     } else {
  1946.     /* HBB 981118: avoid crash if hidden3d sees a manually placed key:
  1947.      * simply turn off hidden-lining while we're drawing the key line: */
  1948.     int save_hidden_active = hidden_active;
  1949.     hidden_active = FALSE;
  1950.  
  1951.     clip_move(xl + key_sample_left, yl);
  1952.     clip_vector(xl + key_sample_right, yl);
  1953.     hidden_active = save_hidden_active;
  1954.     }
  1955. }
  1956.  
  1957. static void key_sample_point(xl, yl, pointtype)
  1958. int xl, yl;
  1959. int pointtype;
  1960. {
  1961.     if (!clip_point(xl + key_point_offset, yl)) {
  1962.     (*term->point) (xl + key_point_offset, yl, pointtype);
  1963.     } else {
  1964.     (*term->point) (xl + key_point_offset, yl, pointtype);
  1965.     }
  1966. }
  1967.